#include "jsapi.h"
#include "js-engine.h"
#include "desktopClasses.h"
#include "basicElementClass.h"
#include "mainview-parser.h"
#include <string.h>
#define OPACITY 0.7

extern void desktop_element_cancel_other_items(desktop_element *listbox, desktop_element *selectedItem);
static JSBool listitem_new(JSContext *cx, JSObject *obj, uintN argc, jsval *args, jsval *rval);
static gboolean draw_listitem(GtkWidget *widget, GdkEvent *event, gpointer ptr);

struct JSFunctionSpec listitem_methods[] = {
    {NULL, NULL}
};

JSClass listitemClass =
    { "listitem", JSCLASS_HAS_PRIVATE,
      JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, 
      JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
      JSCLASS_NO_OPTIONAL_MEMBERS
    };

struct property_parser listitem_parser[] = {
    /* from basicElement */
    {"cursor", set_property_string_value},
    {"dropTarget", set_property_boolean_value},
    {"enabled", set_property_boolean_value},
    {"height", set_property_integer_value},
    {"hitTest", set_property_string_value},
    {"mask", set_property_string_value},
    {"name", set_property_string_value},
    {"offsetHeight", set_property_integer_value},
    {"offsetWidth", set_property_integer_value},
    {"offsetX", set_property_integer_value},
    {"offsetY", set_property_integer_value},
    {"opacity", set_property_integer_value},
    {"pinX", set_property_integer_value},
    {"pinY", set_property_integer_value},
    {"rotation", set_property_float_value},
    {"tagName", set_property_string_value},
    {"tooltip", set_property_string_value},
    {"width", set_property_integer_value},
    {"visible", set_property_boolean_value},
    {"x", set_property_integer_value},
    {"y", set_property_integer_value},
		
    {"background", set_property_string_value},
    {"selected", set_property_boolean_value},
    {NULL, NULL},
};

static JSBool listitem_new(JSContext *cx, JSObject *obj, uintN argc, jsval *args, jsval *rval)
{
    return JS_TRUE;
}

JSObject *listitemClass_init(js_engine *engine, JSObject *parent)
{
    JSObject *proto = NULL;
    proto = JS_InitClass(engine->cx, engine->glob, parent,
			 &listitemClass, listitem_new,
			 0,NULL,NULL,NULL,NULL);
    g_return_val_if_fail(proto, FALSE);
    g_return_val_if_fail(JS_DefineFunctions(engine->cx, proto, listitem_methods), FALSE);
    return proto;
}

gboolean draw_listitem(GtkWidget *widget, GdkEvent *event, gpointer ptr)
{
    desktop_element *element, *parent, *child;
    cairo_t *cr;
    jsval selected, itemOverColor;
    gdouble red = 0, green = 0, blue = 1;

    if(widget == NULL || widget->window == NULL)
	return FALSE;
    element = (desktop_element *)ptr;
    parent = element->parent;
    child = g_list_nth_data(element->children,0);

    cr = gdk_cairo_create(widget->window);
    JS_GetProperty(element->engine->cx, element->jsobj, 
		   "selected", &selected);
    JS_GetProperty(parent->engine->cx, parent->jsobj, 
		   "itemOverColor", &itemOverColor);

    if(JSVAL_IS_STRING(itemOverColor)){
	gchar *color = g_strdup(JS_GetStringBytes(JSVAL_TO_STRING(itemOverColor)));
	if(strlen(color) == 7 && color[0] == '#'){
	    blue = (gdouble)g_ascii_strtoull(&color[5], NULL, 16)/255;
	    color[5] = '\0';
	    green = (gdouble)g_ascii_strtoull(&color[3], NULL, 16)/255;
	    color[3] = '\0';
	    red = (gdouble)g_ascii_strtoull(&color[1], NULL, 16)/255;
	}
	g_free(color);
    }

    if(JSVAL_IS_BOOLEAN(selected)){
	if(JSVAL_TO_BOOLEAN(selected) == JS_TRUE){
	    cairo_pattern_t *cover = 
		cairo_pattern_create_rgba(red, green, blue, OPACITY);
	    cairo_set_source(cr,cover);
	    cairo_paint(cr);
	}
    }
    cairo_destroy(cr);

    return FALSE;
}

gboolean listitem_select_cb(GtkWidget *widget, GdkEventButton *event, gpointer ptr)
{
    desktop_element *element = (desktop_element *)ptr;
    desktop_element *parent_listbox = (desktop_element *)element->parent;
    jsval selected;
    JS_GetProperty(element->engine->cx, element->jsobj, "selected", &selected);
    if(event->type == GDK_BUTTON_RELEASE && event->button == 1){
	if(JSVAL_IS_BOOLEAN(selected) && JSVAL_TO_BOOLEAN(selected) == JS_TRUE){
	}else{
	    selected = JSVAL_TRUE;
	    JS_SetProperty(element->engine->cx, element->jsobj, 
			   "selected", &selected);
	    draw_listitem(element->view, NULL, element);
	}
	desktop_element_cancel_other_items(parent_listbox, element);
    }
    return FALSE;
}

void desktop_element_set_view_listitem(js_engine *engine, desktop_element *element)
{
    jsval width, height, selected = JSVAL_FALSE, background;
    guint width_val = 40, height_val = 20; /* TODO */

    element->view = gtk_event_box_new();
    JS_SetProperty(engine->cx, element->jsobj, "selected", &selected);
    JS_GetProperty(engine->cx, element->jsobj, "width", &width);
    JS_GetProperty(engine->cx, element->jsobj, "height", &height);
    JS_GetProperty(engine->cx, element->jsobj, "background", &background);

    g_signal_connect(element->view, "expose-event", 
		     G_CALLBACK(draw_listitem), element);
    g_signal_connect(element->view, "button-release-event", 
		     G_CALLBACK(listitem_select_cb), element);
    set_element_event_cb(element);
    if(JSVAL_IS_INT(width))
	width_val = JSVAL_TO_INT(width);
    if(JSVAL_IS_INT(height))
	height_val = JSVAL_TO_INT(height);
    gtk_widget_set_size_request(element->view, width_val, height_val);
}
